---
title: "캐시 지우기 및 상태 폐기(disposal)에 반응하기"
version: 1
---

import { Link } from "/src/components/Link";
import { AutoSnippet, When } from "/src/components/CodeSnippet";
import onDisposeExample from "/docs/essentials/auto_dispose/on_dispose_example";
import codegenKeepAlive from "!!raw-loader!/docs/essentials/auto_dispose/codegen_keep_alive.dart";
import rawAutoDispose from "!!raw-loader!/docs/essentials/auto_dispose/raw_auto_dispose.dart";
import invalidateExample from "!!raw-loader!/docs/essentials/auto_dispose/invalidate_example.dart";
import keepAlive from "/docs/essentials/auto_dispose/keep_alive";
import cacheForExtension from "!!raw-loader!/docs/essentials/auto_dispose/cache_for_extension.dart";
import cacheForUsage from "/docs/essentials/auto_dispose/cache_for_usage";
import invalidateFamilyExample from '/docs/essentials/auto_dispose/invalidate_family_example'

지금까지 일부 상태(state)를 생성하거나 업데이트하는 방법을 살펴보았습니다.
하지만 언제 상태가 소멸(destruction)되는지에 대해서는 아직 이야기하지 않았습니다.

Riverpod은 상태 폐기(disposal)와 상호작용할 수 있는 다양한 방법을 제공합니다.
여기에는 상태 폐기를 지연(delaying)시키는 것부터 소멸에 반응하는 것까지 다양합니다.

## 상태는 언제 파괴되며, 그 것을 어떻게 변경하나요?

<When codegen={true}>

코드 생성(code-generation)을 사용할 때 기본적으로 provider가 수신이 중지되면 상태가 파괴됩니다.  
이는 리스너에 전체 프레임에 대한 활성 리스너가 없을 때 발생합니다. 이 경우 상태가 소멸됩니다.

이 동작은 `keepAlive: true`를 사용하여 해제(opted out)할 수 있습니다.  
이렇게 하면 모든 리스너가 제거될 때 상태가 소멸되는 것을 방지할 수 있습니다.

<AutoSnippet 
  raw={codegenKeepAlive} 
  translations={{
    keepAlive: "// 어노테이션에 \"keepAlive\"를 지정하여 자동 상태 소멸을 비활성화할 수 있습니다.",
  }}
/>

</When>

<When codegen={false}>

코드 생성을 사용하지 않는 경우 기본적으로 provider의 수신이 중단되어도 상태는 파괴되지 않습니다.

선택적으로 이 동작을 변경하여 자동 폐기를 사용할 수 있습니다.
그렇게 하면, Riverpod은 provider에 리스너가 있는지 여부를 추적합니다.
그런 다음 provider에 전체 프레임에 대한 리스너가 없는 경우 상태가 삭제됩니다.

자동 폐기를 활성화하려면 provider 타입 옆에 `.autoDispose`를 사용하면 됩니다:

<AutoSnippet 
  raw={rawAutoDispose} 
  translations={{
    autoDispose: "// 자동 상태 파기를 활성화하려면 autoDispose를 지정할 수 있습니다.",
  }}
/>

</When>

:::note
자동 폐기를 활성화/비활성화해도 provider가 다시 계산될 때 상태가 소멸되는지 여부에는 영향을 미치지 않습니다.  
provider가 다시 계산될 때 상태는 항상 소멸(destroyed)됩니다.
:::

:::caution
provider가 매개변수를 받을 때 자동 폐기를 활성화하는 것이 좋습니다.
그렇지 않으면 매개변수 조합당 하나의 상태가 생성되어 메모리 누수가 발생할 수 있기 때문입니다.
:::

## 상태 폐기(disposal)에 대한 반응

Riverpod에는 상태를 파기하는 몇 가지 기본 제공 방법이 있습니다:

- provider가 더 이상 사용되지 않고 "auto dispose" 모드에 있는 경우(자세한 내용은 나중에 설명).
  이 경우 provider와 관련된 모든 상태가 소멸됩니다.
- `ref.watch`와 같이 provider가 다시 계산됩니다.
  이 경우 이전 상태가 폐기되고 새 상태가 생성됩니다.

두 경우 모두. 이 경우 몇 가지 로직을 실행하고 싶을 수 있습니다.  
이는 `ref.onDispose`로 가능합니다. 이 메서드를 사용하면 상태가 소멸될 때마다 리스너를 등록할 수 있습니다.

예를 들어, 이 메서드를 사용해 활성화된 `StreamController`를 닫을 수 있습니다:

<AutoSnippet 
  {...onDisposeExample} 
  translations={{
    onDispose: "  // 상태가 소멸되면 스트림 컨트롤러를 닫습니다.",
    todo: "  // TO-DO: StreamController에 일부 값을 푸시합니다.",
  }}
/>

:::caution
`ref.onDispose`의 콜백은 부작용을 유발하지 않아야 합니다.
`onDispose` 내에서 providers를 수정하면 예기치 않은 동작이 발생할 수 있습니다.
:::

:::info
다음과 같은 다른 유용한 수명 주기(life-cycles)가 있습니다:

- provider의 마지막 리스너가 제거될 때 호출되는 `ref.onCancel`.
- `onCancel`이 호출된 후 새 리스너가 추가될 때 호출되는 `ref.onResume`.

:::

:::info
`ref.onDispose`는 원하는 횟수만큼 호출할 수 있습니다.
provider의 Disposable 객체당 한 번씩 호출해도 됩니다.
이렇게 하면 물건을 버리는 것(dispose of something)을 잊어버렸을 때 쉽게 알아차릴 수 있습니다.
:::

## `ref.invalidate`를 사용하여 provider를 수동으로 강제 삭제하기

때로는 provider를 강제로 파괴하고 싶을 때가 있습니다.
다른 provider나 위젯에서 호출할 수 있는 `ref.invalidate`를 사용하여 수행할 수 있습니다.

`ref.invalidate`를 사용하면 현재 provider 상태가 파괴됩니다.
그러면 두 가지 결과가 발생할 수 있습니다:

- provider가 청취되고 있으면 새 상태가 생성됩니다.
- provider를 청취되고 있지 않으면 provider가 완전히 소멸됩니다.

<AutoSnippet 
  raw={invalidateExample} 
  translations={{
    invalidate: "        // 클릭 시 provider를 파괴(destroy)합니다.",
  }}
/>

:::info
provider가 `ref.invalidateSelf`를 사용하여 스스로 무효화할 수 있습니다.
이 경우 항상 새로운 상태가 생성됩니다.
:::

:::tip
매개변수를 수신하는 provider를 무효화하려고 할 때,
특정 매개변수 조합 하나를 무효화하거나 모든 매개변수 조합을 한 번에 무효화할 수 있습니다:

<AutoSnippet 
  {...invalidateFamilyExample} 
  translations={{
    invalidateAll: "  // 이 provider의 가능한 모든 매개변수 조합을 무효화합니다.",
    invalidate: "  // 특정 조합만 무효화",
  }}
/>
:::

## `ref.keepAlive`를 사용하여 폐기(disposal)를 조정하기

위에서 언급했듯이 자동 폐기를 사용하도록 설정하면 provider에 전체 프레임에 대한 리스너가 없는 경우 상태가 삭제됩니다.

하지만 이 동작을 보다 세밀하게 제어하고 싶을 수도 있습니다. 
예를 들어, 성공한 네트워크 요청의 상태는 유지하되 실패한 요청은 캐시하지 않으려 할 수 있습니다.

이는 자동 폐기를 활성화한 후 `ref.keepAlive`를 사용하면 가능합니다.
이 함수를 사용하면 상태의 자동 폐기를 중지하는 _시점_을 결정할 수 있습니다.

<AutoSnippet 
  {...keepAlive} 
  translations={{
    keepAlive: "  // 요청이 성공적으로 완료된 후에만 provider를 살아있게(alive) 유지합니다.\n  // 요청이 실패한(그리고 예외를 throw한) 경우, provider의 수신(listen)이 중단되면 상태가 파괴됩니다.",
    closeLink: "  // `link`를 사용하여 auto-dispose 동작을 복원(restore)할 수 있습니다:",
  }}
/>

:::note
provider가 다시 계산되면 자동 폐기가 다시 활성화됩니다.

`ref.keepAlive`의 반환 값을 사용하여 자동 폐기로 되돌릴 수도 있습니다.
:::

## 예: 특정 시간 동안 상태를 살아있게 유지하기

현재 Riverpod은 특정 시간 동안 상태를 유지하는 내장된 방법을 제공하지 않습니다.  
하지만 지금까지 살펴본 도구를 사용하면 이러한 기능을 쉽게 구현하고 재사용할 수 있습니다.

`Timer` + `ref.keepAlive`를 사용하면 특정 시간 동안 상태를 유지할 수 있습니다.
이 로직을 재사용할 수 있게 하려면 확장 메서드(extension method)로 구현하면 됩니다:

<AutoSnippet 
  raw={cacheForExtension} 
  translations={{
    cacheFor: "/// [duration] 동안 provider를 살아있게 유지합니다.",
    keepAlive: "    // 상태가 파괴되는 것을 즉시 방지합니다.",
    timer: "    // 기간이 경과하면 자동 폐기를 다시 활성화합니다.",
    onDispose: "    // 선택 사항: provider가 다시 계산될 때(예: ref.watch 사용),\n    // 보류 중인 타이머를 취소합니다.",
  }}
/>

그러면 이렇게 사용할 수 있습니다:

<AutoSnippet 
  {...cacheForUsage} 
  translations={{
    cacheFor: "  /// 5분 동안 상태를 유지합니다.",
  }}
/>

이 로직은 필요에 맞게 조정할 수 있습니다. 
예를 들어 `ref.onCancel`/`ref.onResume`을 사용하여 특정 시간 동안 provider가 수신 대기하지 않은 경우에만 상태를 삭제할 수 있습니다.
